package fr.ece.ing4.si.multithread;


import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import fr.ece.ing4.si.gui.Window;


public class MonteCarloSimulation2 {
	
	public double MonteCarloStandardOption( String CallPutFlag,double s, double x,double t,double r,double b,double v,int nSteps,int nSimulations)
    {
       
        double dt;
        double st;
        double sum = 0;
        double drift;
        double vSqrdt;
        int i;
        int j;
        int z = 0;
        Random ra=new Random();
       
            dt=t/nSteps;
            drift=(b-((v*v)/2))*dt;
            vSqrdt=v*Math.sqrt(dt);
       
            if(CallPutFlag.equals("c"))
            {
                z=1;
            }
       
            else if(CallPutFlag.equals("p"))
            {
                z=-1;
            }
   
           
                    st=s;
                    for(j=1;j<=nSteps;j++)
                    {
                        st=st*Math.exp(drift+vSqrdt * ra.nextGaussian());
                    }
                    	sum=sum+Math.max(z*(st-x),0);
           
       
           
            return (Math.exp(-r*t)*(sum/nSimulations));
        }

   
	 public double MultiMonteCarlo2(final String CallPutFlag,final double s, final double x,final double t,final double r,final double b,final double v,final int nSteps,final int nSimulations) throws InterruptedException, ExecutionException, IOException
	    {
	        double premium = 0.0;
	       
	        final List<Callable<Double>> test =  new ArrayList<Callable<Double>>();
	       
	       
	       
	        final int cores=Runtime.getRuntime().availableProcessors();
	        final double blockingCoefficient = 0.1;
	        final int poolSize = (int)(cores / (1 - blockingCoefficient));
	        System.out.println("Number of Cores available is " + cores);
	        System.out.println("Pool size is " + poolSize);
	        //premium=MonteCarloStandardOption("c",40,50,0.06,0.5,0.10,0.45,168,100);
	       
	        final BufferedReader reader =  new BufferedReader(new FileReader("simulation.txt"));
	        final String info=reader.readLine();
	        final String [] data=info.split(",");



	for (int i=0; i<Integer.valueOf(data[8]);i++){
	    test.add(new Callable<Double>() {
	       
	         public Double call() throws Exception {
	                return MonteCarloStandardOption(CallPutFlag,s,x,t,r,b,v,nSteps,nSimulations);
	            }
	        });
	        }
	       
	        final ExecutorService executorPool =  Executors.newFixedThreadPool(poolSize);   
	        final List<Future<Double>> valueOfStocks = executorPool.invokeAll(test, 10000, TimeUnit.SECONDS);
	       
	        for(final Future<Double> valueOfAStock : valueOfStocks) 
	            premium += valueOfAStock.get();
	        executorPool.shutdown();
	        return premium;
	       
	       
	       
	       
	        //return premium;
	    }
	
	
	
	
	
	
    public double MultiMonteCarlo() throws InterruptedException, ExecutionException, IOException
    {
        double premium = 0.0;
       
        final List<Callable<Double>> test =  new ArrayList<Callable<Double>>();
       
       
       
        final int cores=Runtime.getRuntime().availableProcessors();
        final double blockingCoefficient = 0.1;
        final int poolSize = (int)(cores / (1 - blockingCoefficient));
        System.out.println("Number of Cores available is " + cores);
        System.out.println("Pool size is " + poolSize);
        //premium=MonteCarloStandardOption("c",40,50,0.06,0.5,0.10,0.45,168,100);
       
        final BufferedReader reader =  new BufferedReader(new FileReader("simulation.txt"));
        final String info=reader.readLine();
        final String [] data=info.split(",");



for (int i=0; i<Integer.valueOf(data[8]);i++){
    test.add(new Callable<Double>() {
       
         public Double call() throws Exception {
                return MonteCarloStandardOption(data[0],Double.valueOf(data[1]),Double.valueOf(data[2]),Double.valueOf(data[3]),Double.valueOf(data[4]),Double.valueOf(data[5]),Double.valueOf(data[6]),Integer.valueOf(data[7]),Integer.valueOf(data[8]));
            }
        });
        }
       
        final ExecutorService executorPool =  Executors.newFixedThreadPool(poolSize);   
        final List<Future<Double>> valueOfStocks = executorPool.invokeAll(test, 10000, TimeUnit.SECONDS);
       
        for(final Future<Double> valueOfAStock : valueOfStocks) 
            premium += valueOfAStock.get();
        executorPool.shutdown();
        return premium;
       
       
       
       
        //return premium;
    }
   
    public static void main(final String [] args)
    {
           
        javax.swing.SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                //Variable declaration
                long startTime;
                long endTime;
               
                Window w = null;
				try {
					w = new Window();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
                w.setVisible(true);   
                startTime=System.currentTimeMillis();
                MonteCarloSimulation2 m=new MonteCarloSimulation2();
               
                try {
                   
                    w.setLabel(String.valueOf(m.MultiMonteCarlo()));
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
               
                endTime=System.currentTimeMillis();
                   
                System.out.println("Execution time(in ms) = " + (endTime-startTime));
                }
     
                    });
                }
                   
            }
